package com.qcby.mycommunity_003.controller;

import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qcby.mycommunity_003.aspect.LogAspect;
import com.qcby.mycommunity_003.entity.User;
import com.qcby.mycommunity_003.form.LoginForm;
import com.qcby.mycommunity_003.service.UserService;
import com.qcby.mycommunity_003.util.JwtUtil;
import com.qcby.mycommunity_003.util.Result;
import com.wf.captcha.SpecCaptcha;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;


/**
 * 登录模块业务的所有方法，控制层接口
 * restcontroller直接返回json格式的对象（responsebody也可以）
 */
@RestController
public class LoginController {

    @Autowired
    private RedisTemplate redisTemplate;
    /**
     * 获取验证码
     * @return
     */
    @GetMapping("/captcha")
    public Result getCaptcha(){
        //1.uuid生成验证码
        SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 4);
        //转成小写，（以方便存在redis中）这种做法有bug，如果是小写就出错了
//        改成大写
        String code = specCaptcha.text().toUpperCase();
        String uuid = IdUtil.simpleUUID();//uuid让验证码有唯一的id
        //2.存在缓存数据库redis中并设置超时时间
        // （同时校验时不时无效锁定用户）
        this.redisTemplate.opsForValue().set(uuid,code,120, TimeUnit.SECONDS);
        //3.将验证码返回前端
        //构建map返回前端
        Map<String,String > map=new HashMap<>();
        map.put("uuid",uuid);
        map.put("captcha",specCaptcha.toBase64());
        map.put("code",code);
        return Result.ok().put("data",map);
    }
    @Autowired
    private UserService userService;
    @Autowired
    private JwtUtil jwtUtil;
    /**
     * 登录功能
     * @return
     */
//    @LogAnnotation("用户登录")
    @PostMapping("/login")
    public Result login(@RequestBody LoginForm loginForm, HttpSession session){
        //1.验证用户名
        QueryWrapper<User> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("username",loginForm.getUsername());
        User user = this.userService.getOne(queryWrapper);
        if(user==null){
            return Result.error("用户不存在");
        }
        //2.验证密码，以及进行密码加密
        String password= SecureUtil.sha256(loginForm.getPassword());
        if(!password.equals(user.getPassword())){
            return Result.error("密码错误");
        }
        if(user.getStatus()==0){
            return Result.error("用户被锁定，无法登录！！");
        }
        session.setAttribute("user",user);
        //3.验证码校验
        //通过uuid获取验证码
        String code= (String) this.redisTemplate.opsForValue().get(loginForm.getUuid());
        if(code==null){
//            return Result.ok().put("s")
            return Result.error("验证码过期");
        }
        //和redis库中的对比
        if(!code.equals(loginForm.getCaptcha().toLowerCase()) && !code.equals(loginForm.getCaptcha().toUpperCase())){
            return Result.error("验证码输入错误");
        }
        //4.创建token令牌（有时效）
        String token = this.jwtUtil.createToken(String.valueOf(user.getUserId()));
        this.redisTemplate.opsForValue().set("communityuser-"+user.getUserId(), token,jwtUtil.getExpire());
        HashMap<String,Object> hashMap=new HashMap<>();
        hashMap.put("token",token);
        hashMap.put("expire",jwtUtil.getExpire());
        LogAspect.user=user;
        return Result.ok().put("data",hashMap);
    }

    /**
     * 校验token，为什么要校验token？
     * 因为不能登录一次就永远永久的登录权限（有人借了你的令牌，不能已经他都有权限了）
     * @return
     */
    @GetMapping("/checkToken")
    public Result chencktoken(HttpServletRequest request){
        //1.token存放在请求头当中（前端做的），客户端访问服务端cookie中存信息（token）
        String token = request.getHeader("token");
        //2.和redis当中的token对比，判断token是否有效
        //使用jwt校验token的方式进行校验token（直接查询前端的token是否失效不用再查redis）
        //如果不向redis中存入，直接放回前端token和超时时间？？？？（好像也可以）
        //可以添加一个在redis中查询是否存在的逻辑（更严谨）
        boolean result = jwtUtil.checkToken(token);
        if(result){
            return Result.ok().put("status","ok");
        }else{
            return Result.ok().put("status","error");
        }
    }

    /**
     * 登出
     * @return
     */
//    @LogAnnotation("用户账号登出")
    @PostMapping("/logout")
    public Result logout(HttpSession session){
        //让session无效
        session.invalidate();
        return Result.ok();
    }
}
